#include "SelectCommand.h"


SelectCommand::SelectCommand(SQLSystem* sql): Command(sql)
{
}


SelectCommand::~SelectCommand(void)
{
}

//SELECT * FROM TABLENAME
//SELECT * FROM TABLENAME WHERE ...
//SELECT COLUMN1, COLUMN2,... FROM TABLENAME
//SELECT COLUMN1, COLUMN2,... FROM TABLENAME WHERE ...
int SelectCommand::execute(const string &str)
{
	vector<Row *> selectedRows;
	vector<string> columnsToDisplay;
	bool allColumn=false;
	Table* table;
	SQLSystem* system= getSystem();
	typedef tokenizer<char_separator<char> > token;
	char_separator<char> sep(" ",",",drop_empty_tokens);
	token tok(str, sep);
	token::iterator tok_iter= tok.begin();
	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	if(*tok_iter == "*")
	{
		++tok_iter;
		if(tok_iter == tok.end())	
			return false;
		allColumn= true;
	}
	else
	{
		while(helper->toUpperString(*tok_iter)!="FROM")
		{
			columnsToDisplay.push_back(*tok_iter);
			++tok_iter;
			if(tok_iter == tok.end())	
				return false;
			if(*tok_iter == ",")
			{
				++tok_iter;
				continue;
			}
		}
		
	}

	++tok_iter;
	if(tok_iter == tok.end())	
		return false;
	table= system->getTableByName(*tok_iter);
	if(!table)
	{
		cout << "TABLE NOT FOUND\n";
		return false;
	}
	if(allColumn)
		columnsToDisplay= table->getColumns();
	
	//WHERE part
	++tok_iter;
	//if token ends here, no where part
	//print the whole table with selected columns
	if(tok_iter == tok.end())
	{
		vector<int> types= table->getTypes();
		selectedRows= table->getRows();
		displaySelectedRows(columnsToDisplay, selectedRows, types, table);
		return true;
	}
	if(helper->toUpperString(*tok_iter) != "WHERE")
	{
		cout << "MISSING WHERE STATEMENT\n";
		return false;
	}
	++tok_iter;
	string s;

	//after this loop s will contains the where part of the command
	//without any spaces
	while(tok_iter!=tok.end())
	{
		if((*tok_iter)[0] == '\"')
		{
			string vString;	//this new string contains the real data without the double quote
			unsigned int i=1;
			while((*tok_iter)[i] !='\"')	//to add "tien phat" we need to merge the two token "tien and phat"
			{
				vString +=(*tok_iter)[i];
				++i;
				if(i >= (*tok_iter).size())
				{
					vString += " "; //add space between two words
					++tok_iter;	//next token to continue merging the string
					i=0;	//set i=0 so in the while condition we check again from the start
					continue;
				}
			}
			s +=vString;
		}
		else
			s +=*tok_iter;
		++tok_iter;
	}
	//create wherePart object to get selected rows from a wherePart string and a Table
	WherePart whereClause;
	whereClause.selectRows(s, table);
	selectedRows= whereClause.getSelectedRows();
	vector<int> types= table->getTypes();
	
	//call function displaySelectedRows to print the columns in columnsToDisplay of the selected rows
	displaySelectedRows(columnsToDisplay, selectedRows, types, table);
	return true;
}



void SelectCommand::displaySelectedRows(vector<string> columnsToDisplay, vector<Row *> rowsToDisplay, vector<int> typeOfCells, Table* table)
{
	vector<int> indexOfColumns;
	for(unsigned int i=0;i<columnsToDisplay.size();i++)
	{
		cout << setw(10) <<std::right;
		cout << columnsToDisplay[i] << "\t";
		int index= table->getColumnIndex(columnsToDisplay[i]);
		if(index != -1)
			indexOfColumns.push_back(index);
	}
	cout << endl;

	for(unsigned int j=0;j<rowsToDisplay.size();j++)
	{
		for(unsigned i=0;i<indexOfColumns.size();i++)
		{
			vector<Cell *> cells= rowsToDisplay[j]->getCells();
			Cell* cell= cells[indexOfColumns[i]];
			cout << setw(10) <<std::right;
			if(typeOfCells[indexOfColumns[i]] == VARCHAR)
			{
				VarcharCell* vCell= dynamic_cast<VarcharCell *>(cell);								
				if(!vCell)
				{
					NullCell* nCell= dynamic_cast<NullCell *>(cell);
					//this if to check if the cell is not of any legal data type
					if(!nCell)
					{
						cout << "NULL pointer" <<endl;
						return;
					}
					cout << "NULL" << "\t";
					continue;	//missing this cause troule 'cause you continue to extract data from a null cell->>exception
				}
				string data= vCell->getData();
				cout << data << "\t";
			}
			else if(typeOfCells[indexOfColumns[i]] == INT)
			{
				IntCell* iCell= dynamic_cast<IntCell *>(cell);
				if(!iCell)
				{
					NullCell* nCell= dynamic_cast<NullCell *>(cell);
					if(!nCell)
					{
						cout << "NULL pointer" <<endl;
						return;
					}
					cout << "NULL" << "\t";
					continue;	//missing this cause troule 'cause you continue to extract data from a null cell->>exception
				}
				int data= iCell->getData();
				cout << data << "\t";
			}
		}
		cout << endl;
	}
	cout << endl;
}
